home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CUCD / Games / ADoomPPC / src / amiga_video.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-19  |  34.7 KB  |  1,207 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #include <exec/exec.h>
  6. #include <dos/dos.h>
  7. #include <graphics/gfx.h>
  8. #include <graphics/gfxbase.h>
  9. #include <graphics/gfxmacros.h>
  10. #include <intuition/intuition.h>
  11. #include <libraries/asl.h>
  12. #include <libraries/lowlevel.h>
  13. #include <cybergraphics/cybergraphics.h>
  14. #include <devices/gameport.h>
  15. #include <devices/keymap.h>
  16.  
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/graphics.h>
  20. #include <proto/layers.h>
  21. #include <proto/intuition.h>
  22. #include <proto/asl.h>
  23. #include <proto/keymap.h>
  24. #include <proto/lowlevel.h>
  25. #include <proto/cybergraphics.h>
  26.  
  27. #ifdef GRAFFITI
  28. #include "graffiti.h"
  29. #include "graffiti_lib.h"
  30. #include "graffiti_protos.h"
  31. #endif
  32.  
  33. #include "doomtype.h"
  34. #include "doomdef.h"
  35. #include "doomstat.h"
  36. #include "i_system.h"
  37. #include "i_video.h"
  38. #include "v_video.h"
  39. #include "m_argv.h"
  40. #include "m_bbox.h"
  41. #include "d_main.h"
  42.  
  43. #include "amiga_sega.h"
  44. #include "r_draw.h"
  45. #include "w_wad.h"
  46. #include "z_zone.h"
  47.  
  48. /**********************************************************************/
  49. extern void ppctimer (unsigned int *time);
  50. extern int bus_MHz;
  51.  
  52. extern struct ExecBase *SysBase;
  53. struct Library *AslBase = NULL;
  54. struct Library *CyberGfxBase = NULL;
  55. struct Library *LowLevelBase = NULL;
  56. struct Library *KeymapBase = NULL;
  57.  
  58. extern int cpu_type;
  59.  
  60. int SCREENWIDTH;
  61. int SCREENHEIGHT;
  62. int weirdaspect;
  63.  
  64.  
  65. #define NUMPALETTES 14
  66.  
  67. static struct ScreenModeRequester *video_smr = NULL;
  68. static struct Screen *video_screen = NULL;
  69. static struct Window *video_window = NULL;
  70.  
  71. static int video_mod = 320;
  72. static ULONG video_pixfmt = PIXFMT_LUT8;
  73. static ULONG *video_buffer = NULL;
  74.  
  75. static int video_depth = 8;
  76.  
  77. static FAR ULONG video_colourtable[NUMPALETTES][1 + 3*256 + 1];
  78. static int video_palette_index = 0;
  79. static int video_pending_palette_index = 0;
  80. static volatile WORD video_palette_changed = 0;
  81.  
  82. static BOOL video_is_cyber_mode = FALSE;
  83. static BOOL video_is_directcgx = FALSE;
  84. static BOOL video_doing_fps = FALSE;
  85. static APTR video_bitmap_handle;
  86.  
  87. static struct RastPort video_temprp;
  88. static struct BitMap video_tmp_bm = {
  89.   0, 0, 0, 0, 0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
  90. };
  91.  
  92. static UWORD *emptypointer;
  93.  
  94. /* keyboard */
  95. static BOOL video_is_rawkey;
  96.  
  97. /* gameport stuff */
  98. static struct MsgPort *gameport_mp = NULL;
  99. static struct IOStdReq *gameport_io = NULL;
  100. static BOOL gameport_is_open = FALSE;
  101. static BOOL gameport_io_in_progress = FALSE;
  102. static struct InputEvent gameport_ie;
  103. static BYTE gameport_ct;        /* controller type */
  104. struct GamePortTrigger gameport_gpt = {
  105.   GPTF_UPKEYS | GPTF_DOWNKEYS,    /* gpt_Keys */
  106.   0,                /* gpt_Timeout */
  107.   1,                /* gpt_XDelta */
  108.   1                /* gpt_YDelta */
  109. };
  110.  
  111. /* SEGA variables */
  112. static ULONG prevSega;
  113. static BOOL sega3_selected = FALSE;
  114. static BOOL sega6_selected = FALSE;
  115.  
  116. #ifdef GRAFFITI
  117. struct Library *GraffitiBase = NULL;
  118. int video_graffiti = 0;
  119. static struct GRF_Screen *video_grf_screen = NULL;
  120. #endif
  121.  
  122. #ifdef PROFILE
  123. unsigned int profile[32][4];
  124. #endif
  125.  
  126. /****************************************************************************/
  127.  
  128. static unsigned int start_time[2];
  129. static unsigned int wpa8_time = 0;
  130. static unsigned int lock_time = 0;
  131. static unsigned int total_frames = 0;
  132.  
  133. /****************************************************************************/
  134. static __inline void start_timer (void)
  135. {
  136.   ppctimer (start_time);
  137. }
  138.  
  139. /****************************************************************************/
  140. static __inline unsigned int end_timer (void)
  141. {
  142.   unsigned int end_time[2];
  143.  
  144.   ppctimer (end_time);
  145.   if (end_time[1] >= start_time[1])
  146.     return (((end_time[1] - start_time[1]) << 2) / bus_MHz);
  147.   else
  148.     return (((end_time[1] - start_time[1]) << 2) / bus_MHz + 1000000);
  149. }
  150.  
  151. /****************************************************************************/
  152.  
  153. static char *mode_name (ULONG mode)
  154. /* Return a mode name for given mode, compatible with ASL mode requester */
  155. /* Use name in DisplayInfo database if available */
  156. /* else manually construct the name */
  157. {
  158.   APTR handle;
  159.   char *p;
  160.   struct NameInfo nameinfo;
  161.   struct DimensionInfo dimsinfo;
  162.   static char modename[DISPLAYNAMELEN + 4 + 4 + 11 + 1];
  163.  
  164.   p = modename;
  165.   *p = '\0';
  166.   if ((handle = FindDisplayInfo (mode & ~SPRITES)) != NULL) {
  167.     if (GetDisplayInfoData (handle, (UBYTE *)&nameinfo,
  168.                             sizeof(nameinfo), DTAG_NAME,
  169.                             NULL) > sizeof(struct QueryHeader)) {
  170.       p += sprintf (p, "%s", nameinfo.Name);
  171.     } else if (GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
  172.                                    sizeof(dimsinfo), DTAG_DIMS,
  173.                                    NULL) >= 66 /* sizeof(dimsinfo)*/) {
  174.       switch (mode & MONITOR_ID_MASK) {
  175.         case DEFAULT_MONITOR_ID:
  176.           p += sprintf (p, "DEFAULT:");      /* PAL or NTSC??? */
  177.           break;
  178.         case NTSC_MONITOR_ID:
  179.           p += sprintf (p, "NTSC:");
  180.           break;
  181.         case PAL_MONITOR_ID:
  182.           p += sprintf (p, "PAL:");
  183.           break;
  184.         case VGA_MONITOR_ID:
  185.           p += sprintf (p, "MULTISCAN:");
  186.           break;
  187.         case A2024_MONITOR_ID:
  188.           p += sprintf (p, "A2024:");
  189.           break;
  190.         case PROTO_MONITOR_ID:
  191.           p += sprintf (p, "PROTO:");
  192.           break;
  193.         case EURO72_MONITOR_ID:
  194.           p += sprintf (p, "EURO72:");
  195.           break;
  196.         case EURO36_MONITOR_ID:
  197.           p += sprintf (p, "EURO36:");
  198.           break;
  199.         case SUPER72_MONITOR_ID:
  200.           p += sprintf (p, "SUPER72:");
  201.           break;
  202.         case DBLNTSC_MONITOR_ID:
  203.           p += sprintf (p, "DBLNTSC:");
  204.           break;
  205.         case DBLPAL_MONITOR_ID:
  206.           p += sprintf (p, "DBLPAL:");
  207.           break;
  208.         default:
  209.           p += sprintf (p, "(unknown):");
  210.           break;
  211.       }
  212.       p += sprintf (p, "%d x %d",
  213.                     dimsinfo.Nominal.MaxX - dimsinfo.Nominal.MinX + 1,
  214.                     dimsinfo.Nominal.MaxY - dimsinfo.Nominal.MinY + 1);
  215.       if ((mode & HAM_KEY) != 0)
  216.         p += sprintf (p, " HAM");
  217.       if ((mode & EXTRAHALFBRITE_KEY) != 0)
  218.         p += sprintf (p, " EHB");
  219.       if ((mode & LACE) != 0)
  220.         p += sprintf (p, " Interlaced");
  221.     } else {
  222.       p += sprintf (p, "%s", "(unnamed)");
  223.       if ((mode & HAM_KEY) != 0)
  224.         p += sprintf (p, " HAM");
  225.       if ((mode & EXTRAHALFBRITE_KEY) != 0)
  226.         p += sprintf (p, " EHB");
  227.       if ((mode & LACE) != 0)
  228.         p += sprintf (p, " Interlaced");
  229.     }
  230.   } else {
  231.     p += sprintf (p, "%s", "(unavailable)");
  232.   }
  233.   return (modename);
  234. }
  235.  
  236. /****************************************************************************/
  237.  
  238. static ULONG parse_mode (char *modename)
  239. /* Modename may be descriptive name ("PAL Lores"), or hex ("$00420001" or */
  240. /* "0x12345678") or decimal ("32768"). */
  241. {
  242.   ULONG mode, reason;
  243.  
  244.   mode = INVALID_ID;
  245.   if (modename != NULL) {
  246.     if (modename[0] == '0' && modename[1] == 'x') {
  247.       if (sscanf (&modename[2], "%lx", &mode) != 1)
  248.         mode = INVALID_ID;
  249.     } else if (modename[0] == '$') {
  250.       if (sscanf (&modename[1], "%lx", &mode) != 1)
  251.         mode = INVALID_ID;
  252.     } else if (modename[0] >= '0' && modename[0] <= '9') {
  253.       if (sscanf (modename, "%ld", &mode) != 1)
  254.         mode = INVALID_ID;
  255.     } else {
  256.       while ((mode = NextDisplayInfo (mode)) != INVALID_ID) {
  257.         if ((mode & LORESDPF_KEY) == 0) {
  258.           /* printf ("$%08x  \"%s\"\n", mode, mode_name (mode)); */
  259.           if (strcmp (mode_name (mode), modename) == 0)
  260.             break;
  261.         }
  262.       }
  263.     }
  264.   }
  265.   if (FindDisplayInfo (mode) == NULL)
  266.     I_Error ("ScreenMode not in database: \"%s\"", modename);
  267.   if ((reason = ModeNotAvailable (mode)) != 0)
  268.     I_Error ("Mode $%08x is not available: %ld", mode, reason);
  269.   return (mode);
  270. }
  271.  
  272. /**********************************************************************/
  273. static void video_do_fps (struct RastPort *rp, int yoffset)
  274. {
  275.   int x;
  276.   static unsigned int start_time[2] = {0, 0};
  277.   unsigned int end_time[2];
  278.   char msg[4];
  279.  
  280.   ppctimer (end_time);
  281.   if (end_time[1] >= start_time[1])
  282.     x = (((end_time[1] - start_time[1]) << 2) / bus_MHz);
  283.   else
  284.     x = (((end_time[1] - start_time[1]) << 2) / bus_MHz + 1000000);
  285.   if (x != 0) {
  286.     x = (1000000 + (x >> 1)) / x;   /* round to nearest */
  287.     msg[0] = (x % 1000) / 100 + '0';
  288.     msg[1] = (x % 100) / 10 + '0';
  289.     msg[2] = (x % 10) + '0';
  290.     msg[3] = '\0';
  291.     Move (rp, SCREENWIDTH - 24, yoffset + 6);
  292.     Text (rp, msg, 3);
  293.   }
  294.   start_time[1] = end_time[1];
  295. }
  296.  
  297. /**********************************************************************/
  298. // Called by D_DoomMain,
  299. // determines the hardware configuration
  300. // and sets up the video mode
  301. void I_InitGraphics (void)
  302. {
  303.   ULONG propertymask, idcmp, wflags, width, pixfmt;
  304.   struct Rectangle rect;
  305.   char reqtitle[32];
  306.   int mode, depth, nbytes, p;
  307.   DisplayInfoHandle handle;
  308.   struct DisplayInfo dispinfo;
  309.   struct DimensionInfo dimsinfo;
  310.   static struct TextAttr topaz8 = {
  311.     "topaz.font", 8, FS_NORMAL, FPF_ROMFONT
  312.   };
  313.  
  314.   if ((KeymapBase = OpenLibrary ("keymap.library", 0)) == NULL)
  315.     I_Error ("Can't open keymap.library");
  316.  
  317.   video_doing_fps = M_CheckParm ("-fps");
  318.  
  319. #ifdef GRAFFITI
  320.   if (video_graffiti != 0) {
  321.     if ((GraffitiBase = OpenLibrary ("graffiti.library", 0)) == NULL)
  322.       I_Error ("Can't open graffiti.library");
  323.     if ((video_grf_screen = OpenChunkyScreen (video_graffiti)) == NULL)
  324.       I_Error ("graffiti.library OpenChunkyScreen() failed");
  325.     video_screen = (struct Screen *)video_grf_screen->GRF_ScreenID;
  326.     video_depth = 8;
  327.   } else {
  328. #endif
  329.  
  330.     if (AslBase == NULL) {
  331.       if ((AslBase = OpenLibrary ("asl.library", 37L)) == NULL ||
  332.           (video_smr = AllocAslRequestTags (ASL_ScreenModeRequest, TAG_DONE)) == NULL) {
  333.         I_Error ("OpenLibrary(""asl.library"", 37) failed");
  334.       }
  335.     }
  336.  
  337.     CyberGfxBase = OpenLibrary ("cybergraphics.library", 0); /* may be NULL */
  338.  
  339.     /* first check tooltypes for SCREENMODE */
  340.     mode = -1;
  341.     p = M_CheckParm ("-screenmode");
  342.     if (p && p < myargc - 1) {
  343.       mode = parse_mode (myargv[p+1]);
  344.     }
  345.  
  346.     /* if not found in icon tooltypes, then put up a ScreenMode requester */
  347.     if (mode == -1) {
  348.       propertymask = DIPF_IS_EXTRAHALFBRITE | DIPF_IS_DUALPF |
  349.                      DIPF_IS_PF2PRI | DIPF_IS_HAM;
  350.       if (CyberGfxBase != NULL)
  351.         mode = BestCModeIDTags (CYBRBIDTG_NominalWidth, SCREENWIDTH,
  352.                                 CYBRBIDTG_NominalHeight, SCREENHEIGHT,
  353.                                 CYBRBIDTG_Depth,    8,
  354.                                 TAG_DONE);
  355.       else if (GfxBase->LibNode.lib_Version >= 39)
  356.         mode = BestModeID (BIDTAG_NominalWidth,     SCREENWIDTH,
  357.                            BIDTAG_NominalHeight,    SCREENHEIGHT,
  358.                            BIDTAG_Depth,            video_depth,
  359.                            BIDTAG_DIPFMustNotHave,  propertymask,
  360.                            TAG_DONE);
  361.       if (AslBase->lib_Version >= 38) {
  362.         sprintf (reqtitle, "ADoomPPC %dx%d", SCREENWIDTH, SCREENHEIGHT);
  363.         if (!AslRequestTags (video_smr,
  364.                              ASLSM_TitleText,        (ULONG)reqtitle,
  365.                              ASLSM_InitialDisplayID, mode,
  366.                              ASLSM_MinWidth,         SCREENWIDTH,
  367.                              ASLSM_MinHeight,        SCREENHEIGHT,
  368.                              ASLSM_MaxWidth,         MAXSCREENWIDTH,
  369.                              ASLSM_MaxHeight,        MAXSCREENHEIGHT,
  370.                              ASLSM_MinDepth,         8,
  371.                              ASLSM_MaxDepth,         8,
  372.                              ASLSM_PropertyMask,     propertymask,
  373.                              ASLSM_PropertyFlags,    0,
  374.                              TAG_DONE)) {
  375.           I_Error ("AslRequest() failed");
  376.         }
  377.         mode = video_smr->sm_DisplayID;
  378.       }
  379.     }
  380.  
  381.     if ((handle = FindDisplayInfo (mode)) == NULL) {
  382.       I_Error ("Can't FindDisplayInfo() for mode %08x", mode);
  383.     }
  384.     if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dispinfo,
  385.                                       sizeof(struct DisplayInfo), DTAG_DISP,
  386.                                       NULL)) < 40 /*sizeof(struct DisplayInfo)*/) {
  387.       I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
  388.                mode, nbytes);
  389.     }
  390.     if ((nbytes = GetDisplayInfoData (handle, (UBYTE *)&dimsinfo,
  391.                                       sizeof(dimsinfo), DTAG_DIMS,
  392.                                       NULL)) < 66 /* sizeof(dimsinfo)*/) {
  393.       I_Error ("Can't GetDisplayInfoData() for mode %08x, got %d bytes",
  394.                mode, nbytes);
  395.     }
  396.  
  397.     video_is_cyber_mode = 0;
  398.     if (CyberGfxBase != NULL)
  399.       video_is_cyber_mode = IsCyberModeID (mode);
  400.  
  401.     printf ("Screen Mode $%08x is ", mode);
  402.     printf (" 8-BIT");
  403.     if (video_is_cyber_mode)
  404.       printf (" CyberGraphX");
  405.     printf ("\n");
  406.  
  407.     video_depth = 8;
  408.  
  409.     rect.MinX = 0;
  410.     rect.MinY = 0;
  411.     rect.MaxX = SCREENWIDTH - 1;
  412.     rect.MaxY = SCREENHEIGHT - 1;
  413.  
  414.  
  415.     if (video_is_cyber_mode && M_CheckParm ("-directcgx"))
  416.       video_is_directcgx = TRUE;
  417.  
  418.     if ((video_screen = OpenScreenTags (NULL,
  419.           SA_Type,        CUSTOMSCREEN,
  420.           SA_DisplayID,   mode,
  421.           SA_DClip,       (ULONG)&rect,
  422.           SA_Width,       SCREENWIDTH,
  423.           SA_Height,      SCREENHEIGHT,
  424.           SA_Depth,       video_depth,
  425.           SA_Font,        &topaz8,
  426.           /* SA_Draggable,FALSE, */
  427.           /* SA_AutoScroll,FALSE, */
  428.           /* SA_Exclusive,TRUE, */
  429.           SA_Quiet,       TRUE,
  430.           TAG_DONE,       0)) == NULL) {
  431.       I_Error ("OpenScreen() failed");
  432.     }
  433.  
  434.     if (video_is_directcgx) {
  435.       video_bitmap_handle = LockBitMapTags (video_screen->ViewPort.RasInfo->BitMap,
  436.                                             LBMI_WIDTH,       &width,
  437.                                             LBMI_DEPTH,       &depth,
  438.                                             LBMI_PIXFMT,      &pixfmt,
  439.                                             TAG_DONE);
  440.       UnLockBitMap (video_bitmap_handle);
  441.       if (/* width != SCREENWIDTH || */
  442.           depth != video_depth ||
  443.           pixfmt != PIXFMT_LUT8) {
  444.         I_Error ("ScreenMode of width %d, depth %d, pixfmt %d cannot be used with -directcgx",
  445.                  width, depth, pixfmt);
  446.       }
  447.     }
  448.  
  449. #ifdef GRAFFITI
  450.   }
  451. #endif
  452.  
  453.   idcmp = IDCMP_RAWKEY;
  454.   wflags = WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP | WFLG_NOCAREREFRESH |
  455.            WFLG_SIMPLE_REFRESH;
  456.   if (M_CheckParm("-mouse") != NULL) {
  457.     idcmp |= IDCMP_MOUSEMOVE | IDCMP_DELTAMOVE | IDCMP_MOUSEBUTTONS;
  458.     wflags |= WFLG_REPORTMOUSE;
  459.   }
  460.  
  461.   if ((video_window = OpenWindowTags (NULL,
  462.         WA_Left,         0,
  463.         WA_Top,          0,
  464.         WA_Width,        SCREENWIDTH,
  465.         WA_Height,       SCREENHEIGHT,
  466.         WA_IDCMP,        idcmp,
  467.         WA_Flags,        wflags,
  468.         WA_CustomScreen, video_screen,
  469.         TAG_DONE)) == NULL) {
  470.     I_Error ("OpenWindow() failed");
  471.   }
  472.  
  473.   InitBitMap (&video_tmp_bm, video_depth, SCREENWIDTH, 1);
  474.   for (depth = 0; depth < video_depth; depth++)
  475.     if ((video_tmp_bm.Planes[depth] = (PLANEPTR)AllocRaster (SCREENWIDTH, 1)) == NULL)
  476.       I_Error ("AllocRaster() failed");
  477.   video_temprp = *video_window->RPort;
  478.   video_temprp.Layer = NULL;
  479.   video_temprp.BitMap = &video_tmp_bm;
  480.  
  481.   if ((emptypointer = AllocVec (16, MEMF_CHIP+MEMF_CLEAR)) == NULL)
  482.     I_Error ("Couldn't allocate chip memory for pointer");
  483.  
  484.   if (!M_CheckParm ("-mousepointer"))
  485.     SetPointer (video_window, emptypointer, 1, 16, 0, 0);
  486.  
  487.   I_RecalcPalettes ();
  488.  
  489.   /* keyboard & joystick initialisation */
  490.  
  491.   video_is_rawkey = M_CheckParm ("-rawkey");
  492.  
  493.   if (M_CheckParm ("-sega3") != NULL)
  494.     sega3_selected = TRUE;
  495.  
  496.   if (M_CheckParm ("-sega6") != NULL)
  497.     sega6_selected = TRUE;
  498.  
  499.   if (M_CheckParm ("-joypad") != NULL) {
  500.  
  501.     if ((LowLevelBase = OpenLibrary ("lowlevel.library", 0)) == NULL)
  502.       I_Error ("-joypad option specified and can't open lowlevel.library");
  503.  
  504.   } else {
  505.  
  506.     if ((gameport_mp = CreatePort (NULL, 0)) == NULL ||
  507.         (gameport_io = (struct IOStdReq *)CreateExtIO (gameport_mp,
  508.                                               sizeof(struct IOStdReq))) == NULL ||
  509.         OpenDevice ("gameport.device", 1, (struct IORequest *)gameport_io, 0) != 0)
  510.       I_Error ("Can't open gameport.device");
  511.  
  512.     gameport_is_open = TRUE;
  513.  
  514.     Forbid ();
  515.  
  516.     gameport_io->io_Command = GPD_ASKCTYPE;
  517.     gameport_io->io_Length = 1;
  518.     gameport_io->io_Data = &gameport_ct;
  519.     DoIO ((struct IORequest *)gameport_io);
  520.  
  521.     if (gameport_ct != GPCT_NOCONTROLLER) {
  522.  
  523.       Permit ();
  524.       fprintf (stderr, "Another task is using the gameport!  Joystick disabled");
  525.       CloseDevice ((struct IORequest *)gameport_io);
  526.       gameport_is_open = FALSE;
  527.  
  528.     } else {
  529.  
  530.       gameport_ct = GPCT_ABSJOYSTICK;
  531.       gameport_io->io_Command = GPD_SETCTYPE;
  532.       gameport_io->io_Length = 1;
  533.       gameport_io->io_Data = &gameport_ct;
  534.       DoIO ((struct IORequest *)gameport_io);
  535.  
  536.       Permit ();
  537.  
  538.       gameport_io->io_Command = GPD_SETTRIGGER;
  539.       gameport_io->io_Length = sizeof(struct GamePortTrigger);
  540.       gameport_io->io_Data = &gameport_gpt;
  541.       DoIO ((struct IORequest *)gameport_io);
  542.  
  543.       gameport_io->io_Command = GPD_READEVENT;
  544.       gameport_io->io_Length = sizeof (struct InputEvent);
  545.       gameport_io->io_Data = &gameport_ie;
  546.       SendIO ((struct IORequest *)gameport_io);
  547.       gameport_io_in_progress = TRUE;
  548.     }
  549.   }
  550. }
  551.  
  552. /**********************************************************************/
  553. void I_ShutdownGraphics (void)
  554. {
  555.   int depth;
  556.  
  557.   if (LowLevelBase != NULL) {
  558.     CloseLibrary (LowLevelBase);
  559.     LowLevelBase = NULL;
  560.   }
  561.   if (gameport_io_in_progress) {
  562.     AbortIO ((struct IORequest *)gameport_io);
  563.     WaitIO ((struct IORequest *)gameport_io);
  564.     gameport_io_in_progress = FALSE;
  565.     gameport_ct = GPCT_NOCONTROLLER;
  566.     gameport_io->io_Command = GPD_SETCTYPE;
  567.     gameport_io->io_Length = 1;
  568.     gameport_io->io_Data = &gameport_ct;
  569.     DoIO ((struct IORequest *)gameport_io);
  570.   }
  571.   if (gameport_is_open) {
  572.     CloseDevice ((struct IORequest *)gameport_io);
  573.     gameport_is_open = FALSE;
  574.   }
  575.   if (gameport_io != NULL) {
  576.     DeleteExtIO ((struct IORequest *)gameport_io);
  577.     gameport_io = NULL;
  578.   }
  579.   if (gameport_mp != NULL) {
  580.     DeletePort (gameport_mp);
  581.     gameport_mp = NULL;
  582.   }
  583.   if (video_window != NULL) {
  584.     ClearPointer (video_window);
  585.     CloseWindow (video_window);
  586.     video_window = NULL;
  587.   }
  588.   if (emptypointer != NULL) {
  589.     FreeVec (emptypointer);
  590.     emptypointer = NULL;
  591.   }
  592. #ifdef GRAFFITI
  593.   if (video_grf_screen != NULL) {
  594.     CloseChunkyScreen (video_grf_screen);
  595.     video_grf_screen = NULL;
  596.     video_screen = NULL;
  597.   }
  598.   if (GraffitiBase != NULL) {
  599.     CloseLibrary (GraffitiBase);
  600.     GraffitiBase = NULL;
  601.   }
  602. #endif
  603.   if (video_screen != NULL) {
  604.     CloseScreen (video_screen);
  605.     video_screen = NULL;
  606.   }
  607.   for (depth = 0; depth < video_depth; depth++) {
  608.     if (video_tmp_bm.Planes[depth] != NULL) {
  609.       FreeRaster (video_tmp_bm.Planes[depth], SCREENWIDTH, 1);
  610.       video_tmp_bm.Planes[depth] = NULL;
  611.     }
  612.   }
  613.   if (KeymapBase == NULL) {
  614.     CloseLibrary (KeymapBase);
  615.     KeymapBase = NULL;
  616.   }
  617.   if (CyberGfxBase == NULL) {
  618.     CloseLibrary (CyberGfxBase);
  619.     CyberGfxBase = NULL;
  620.   }
  621. }
  622.  
  623. /**********************************************************************/
  624. // recalculate colourtable[][] after changing usegamma
  625. void I_RecalcPalettes (void)
  626. {
  627.   int p, i;
  628.   byte *palette;
  629.   static int lu_palette;
  630.  
  631.   lu_palette = W_GetNumForName ("PLAYPAL");
  632.   for (p = 0; p < NUMPALETTES; p++) {
  633.     palette = (byte *) W_CacheLumpNum (lu_palette, PU_STATIC)+p*768;
  634. #ifdef GRAFFITI
  635.     if (video_graffiti != 0) {
  636.       for (i = 0; i < 256; i++)
  637.         video_colourtable[p][i] =
  638.                     (((UBYTE)gammatable[usegamma][palette[3*i+0]]) << 16) +
  639.                     (((UBYTE)gammatable[usegamma][palette[3*i+1]]) << 8) +
  640.                      ((UBYTE)gammatable[usegamma][palette[3*i+2]]);
  641.     } else {
  642. #endif
  643.       i = 3 * 256 - 1;
  644.       video_colourtable[p][i + 2] = 0;
  645.       do {
  646.         // Better to define c locally here instead of for the whole function:
  647.         ULONG c = gammatable[usegamma][palette[i]];
  648.         c += (c << 8);
  649.         video_colourtable[p][i + 1] = (c << 16) + c;
  650.       } while (--i >= 0);
  651.       video_colourtable[p][0] = (256 << 16) + 0;
  652. #ifdef GRAFFITI
  653.     }
  654. #endif
  655.   }
  656. }
  657.  
  658. /**********************************************************************/
  659. // Takes full 8 bit values.
  660. void I_SetPalette (byte *palette, int palette_index)
  661. {
  662.   video_palette_changed = 1;
  663.   video_palette_index = palette_index;
  664. }
  665.  
  666. /**********************************************************************/
  667. // Called by anything that renders to screens[0] (except 3D view)
  668. void I_MarkRect (int left, int top, int width, int height)
  669. {
  670.   M_AddToBox (dirtybox, left, top);
  671.   M_AddToBox (dirtybox, left + width - 1, top + height - 1);
  672. }
  673.  
  674. /**********************************************************************/
  675. void I_StartUpdate (void)
  676. {
  677. }
  678.  
  679. /**********************************************************************/
  680. void I_UpdateNoBlit (void)
  681. {
  682. }
  683.  
  684. /**********************************************************************/
  685. void I_FinishUpdate (void)
  686. /* This needs optimising to copy just the parts that changed,
  687.    especially if the user has shrunk the playscreen. */
  688. {
  689.   int top, left, width, height;
  690.   UBYTE *base_address;
  691.  
  692.   total_frames++;
  693.  
  694. #ifdef GRAFFITI
  695.   if (video_graffiti != 0) {
  696.     start_timer();
  697.     CopyChunkyScreen (video_grf_screen, screens[0]);
  698.     SetChunkyPalette (video_grf_screen,
  699.                       (long *)video_colourtable[video_palette_index]);
  700.     video_palette_changed = 0;
  701.     ccs_time += end_timer();
  702.     return;
  703.   }
  704. #endif
  705.  
  706.   if (video_is_directcgx) {
  707.     if (video_palette_changed != 0) {
  708.       LoadRGB32 (&video_screen->ViewPort,
  709.                  video_colourtable[video_palette_index]);
  710.       video_palette_changed = 0;
  711.     }
  712.     start_timer ();
  713.     video_bitmap_handle = LockBitMapTags (video_screen->ViewPort.RasInfo->BitMap,
  714.                                             LBMI_BASEADDRESS, &base_address,
  715.                                             TAG_DONE);
  716.     memcpy (base_address, screens[0], SCREENWIDTH * SCREENHEIGHT);
  717.     UnLockBitMap (video_bitmap_handle);
  718.     lock_time += end_timer ();
  719.     if (video_doing_fps)
  720.       video_do_fps (video_window->RPort, 0);
  721.     return;
  722.   }
  723.  
  724.   /* update only the viewwindow and dirtybox when gamestate == GS_LEVEL */
  725.   if (gamestate == GS_LEVEL) {
  726.     if (dirtybox[BOXLEFT] < viewwindowx)
  727.       left = dirtybox[BOXLEFT];
  728.     else
  729.       left = viewwindowx;
  730.     if (dirtybox[BOXRIGHT] + 1 > viewwindowx + scaledviewwidth)
  731.       width = dirtybox[BOXRIGHT] + 1 - left;
  732.     else
  733.       width = viewwindowx + scaledviewwidth - left;
  734.     if (dirtybox[BOXBOTTOM] < viewwindowy) /* BOXBOTTOM is really the top! */
  735.       top = dirtybox[BOXBOTTOM];
  736.     else
  737.       top = viewwindowy;
  738.     if (dirtybox[BOXTOP] + 1 > viewwindowy + viewheight)
  739.       height = dirtybox[BOXTOP] + 1 - top;
  740.     else
  741.       height = viewwindowy + viewheight - top;
  742.     M_ClearBox (dirtybox);
  743. #ifdef RANGECHECK
  744.     if (left < 0 || left + width > SCREENWIDTH ||
  745.         top < 0 || top + height > SCREENHEIGHT)
  746.       I_Error ("I_FinishUpdate: Box out of range: %d %d %d %d",
  747.                left, top, width, height);
  748. #endif
  749.   } else {
  750.     left = 0;
  751.     top = 0;
  752.     width = SCREENWIDTH;
  753.     height = SCREENHEIGHT;
  754.   }
  755.  
  756.   /* not directcgx or graffiti */
  757.   if (video_palette_changed != 0) {
  758.     LoadRGB32 (&video_screen->ViewPort,
  759.                video_colourtable[video_palette_index]);
  760.     video_palette_changed = 0;
  761.   }
  762.   start_timer();
  763.   WritePixelArray8 (video_window->RPort, 0, top, SCREENWIDTH-1,
  764.                     top+height-1, &screens[0][SCREENWIDTH * top],
  765.                     &video_temprp);
  766.   wpa8_time += end_timer();
  767.   if (video_doing_fps)
  768.     video_do_fps (video_window->RPort, 0);
  769. }
  770.  
  771. /**********************************************************************/
  772. // Wait for vertical retrace or pause a bit.  Use when quit game.
  773. void I_WaitVBL(int count)
  774. {
  775.   for ( ; count > 0; count--)
  776.     WaitTOF();
  777. }
  778.  
  779. /**********************************************************************/
  780. void I_ReadScreen (byte* scr)
  781. {
  782.   memcpy (scr, screens[0], SCREENWIDTH * SCREENHEIGHT);
  783. }
  784.  
  785. /**********************************************************************/
  786. void I_BeginRead (void)
  787. {
  788. }
  789.  
  790. /**********************************************************************/
  791. void I_EndRead (void)
  792. {
  793. }
  794.  
  795. /**********************************************************************/
  796.  
  797. int xlate_key (UWORD rawkey, UWORD qualifier, APTR *eventptr)
  798. {
  799.   char buffer[4], c;
  800.   struct InputEvent ie;
  801.   static int xlate[0x68] = {
  802.     '`', '1', '2', '3', '4', '5', '6', '7',
  803.     '8', '9', '0', KEY_MINUS, KEY_EQUALS, '\\', 0, '0',
  804.     'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
  805.     'o', 'p', KEY_F11, KEY_F12, 0, '0', '2', '3',
  806.     'a', 's', 'd', 'f', 'g', 'h', 'j', 'k',
  807.     'l', ';', '\'', KEY_ENTER, 0, '4', '5', '6',
  808.     KEY_RSHIFT, 'z', 'x', 'c', 'v', 'b', 'n', 'm',
  809.     ',', '.', '/', 0, '.', '7', '8', '9',
  810.     ' ', KEY_BACKSPACE, KEY_TAB, KEY_ENTER, KEY_ENTER, KEY_ESCAPE, KEY_F11,
  811.     0, 0, 0, KEY_MINUS, 0, KEY_UPARROW, KEY_DOWNARROW, KEY_RIGHTARROW, KEY_LEFTARROW,
  812.     KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8,
  813.     KEY_F9, KEY_F10, '(', ')', '/', '*', KEY_EQUALS, KEY_PAUSE,
  814.     KEY_RSHIFT, KEY_RSHIFT, 0, KEY_RCTRL, KEY_LALT, KEY_RALT, 0, KEY_RCTRL
  815.   };
  816.  
  817.   if (video_is_rawkey)
  818.     if (rawkey < 0x68)
  819.       return xlate[rawkey];
  820.     else
  821.       return 0;
  822.   else
  823.     if (rawkey > 0x00 && rawkey < 0x0a) // '1'..'9', no SHIFT French keyboards
  824.       return '0' + rawkey;
  825.     else if (rawkey == 0x0a)            // '0'
  826.       return '0';
  827.     else if (rawkey < 0x40) {
  828.       ie.ie_Class = IECLASS_RAWKEY;
  829.       ie.ie_Code = rawkey;
  830.       ie.ie_Qualifier = qualifier;
  831.       ie.ie_EventAddress = *eventptr;
  832.       if (MapRawKey (&ie, buffer, sizeof(buffer), NULL) > 0) {
  833.         c = buffer[0];
  834.         if (c >= '0' && c <= '9')       /* numeric pad */
  835.           switch (c) {
  836.           case '0':
  837.             return ' ';
  838.           case '1':
  839.             return ',';
  840.           case '2':
  841.             return KEY_RCTRL;
  842.           case '3':
  843.             return '.';
  844.           case '4':
  845.             return KEY_LEFTARROW;
  846.           case '5':
  847.             return KEY_DOWNARROW;
  848.           case '6':
  849.             return KEY_RIGHTARROW;
  850.           case '7':
  851.             return ',';
  852.           case '8':
  853.             return KEY_UPARROW;
  854.           case '9':
  855.             return '.';
  856.           }
  857.         else if (c >= 'A' && c <= 'Z')
  858.           return c - 'A' + 'a';
  859.         else if (c == '<')
  860.           return ',';
  861.         else if (c == '>')
  862.           return '.';
  863.         else if (c == '-')
  864.           return KEY_MINUS;
  865.         else if (c == '=')
  866.           return KEY_EQUALS;
  867.         else if (c == '[')
  868.           return KEY_F11;
  869.         else if (c == ']')
  870.           return KEY_F12;
  871.         else if (c == '\r')
  872.           return KEY_ENTER;
  873.         else if (c == '\n')
  874.           return KEY_ENTER;
  875.         else
  876.           return c;
  877.       } else
  878.         return 0;
  879.     } else if (rawkey < 0x68)
  880.       return xlate[rawkey];
  881.     else
  882.       return 0;
  883. }
  884.  
  885. /**********************************************************************/
  886. void amiga_getevents (void)
  887. {
  888.   event_t event;
  889.   ULONG class;
  890.   UWORD code;
  891.   WORD mousex, mousey;
  892.   struct IntuiMessage *msg;
  893.   static ULONG previous = 0;
  894.   static event_t joyevent = {0}, mouseevent = {0};
  895.   ULONG currSega;
  896.   int doomkey;
  897.  
  898.   if (video_window != NULL) {
  899.     while ((msg = (struct IntuiMessage *)GetMsg (video_window->UserPort)) != NULL) {
  900.       class = msg->Class;
  901.       code = msg->Code;
  902.       mousex = msg->MouseX;
  903.       mousey = msg->MouseY;
  904.       if (class == IDCMP_RAWKEY) {
  905.         if ((code & 0x80) != 0) {
  906.           code &= ~0x80;
  907.       event.type = ev_keyup;
  908.         } else {
  909.           event.type = ev_keydown;
  910.         }
  911.         if (code < 0x68)
  912.           doomkey = xlate_key (code, msg->Qualifier, msg->IAddress);
  913.       }
  914.       ReplyMsg ((struct Message *)msg);  /* reply after xlating key */
  915.       if (class == IDCMP_RAWKEY) {
  916.         if (code < 0x68 && doomkey != 0) {
  917.           event.data1 = doomkey;
  918.           D_PostEvent (&event);
  919.           /* printf ("key %02x -> %02x\n", code, doomkey); */
  920.         }
  921.       } else if (class == IDCMP_MOUSEMOVE) {
  922.         mouseevent.type = ev_mouse;
  923.         mouseevent.data2 = (mousex << 3);
  924.         mouseevent.data3 = -(mousey << 5);
  925.         D_PostEvent (&mouseevent);
  926.       } else if (class == IDCMP_MOUSEBUTTONS) {
  927.         mouseevent.type = ev_mouse;
  928.         switch (code) {
  929.           case SELECTDOWN:
  930.             mouseevent.data1 |= 1;
  931.             break;
  932.           case SELECTUP:
  933.             mouseevent.data1 &= ~1;
  934.             break;
  935.           case MENUDOWN:
  936.             mouseevent.data1 |= 2;
  937.             break;
  938.           case MENUUP:
  939.             mouseevent.data1 &= ~2;
  940.             break;
  941.           case MIDDLEDOWN:
  942.             mouseevent.data1 |= 4;
  943.             break;
  944.           case MIDDLEUP:
  945.             mouseevent.data1 &= ~4;
  946.             break;
  947.           default:
  948.             break;
  949.         }
  950.         D_PostEvent (&mouseevent);
  951.       }
  952.     }
  953.   }
  954.  
  955.   if (gameport_is_open && gameport_io_in_progress) {
  956.     while (GetMsg (gameport_mp) != NULL) {
  957.       switch (gameport_ie.ie_Code) {
  958.         case IECODE_LBUTTON:
  959.           joyevent.data1 |= 1;
  960.           break;
  961.         case IECODE_LBUTTON | IECODE_UP_PREFIX:
  962.           joyevent.data1 &= ~1;
  963.           break;
  964.         case IECODE_RBUTTON:
  965.           joyevent.data1 |= 2;
  966.           break;
  967.         case IECODE_RBUTTON | IECODE_UP_PREFIX:
  968.           joyevent.data1 &= ~2;
  969.           break;
  970.         case IECODE_MBUTTON:
  971.           joyevent.data1 |= 4;
  972.           break;
  973.         case IECODE_MBUTTON | IECODE_UP_PREFIX:
  974.           joyevent.data1 &= ~4;
  975.           break;
  976.         case IECODE_NOBUTTON:
  977.           joyevent.data2 = gameport_ie.ie_X;
  978.           joyevent.data3 = gameport_ie.ie_Y;
  979.           break;
  980.         default:
  981.           break;
  982.       }
  983.       joyevent.type = ev_joystick;
  984.       D_PostEvent (&joyevent);
  985.       gameport_io->io_Command = GPD_READEVENT;
  986.       gameport_io->io_Length = sizeof (struct InputEvent);
  987.       gameport_io->io_Data = &gameport_ie;
  988.       SendIO ((struct IORequest *)gameport_io);
  989.     }
  990.   }
  991.  
  992.   /* CD32 joypad handler code supplied by Gabry (ggreco@iol.it) */
  993.  
  994.   if (LowLevelBase != NULL) {
  995.     event_t joyevent;
  996.     ULONG joypos = ReadJoyPort (1);
  997.  
  998.     if (previous == joypos)
  999.       return;
  1000.  
  1001.     joyevent.type = ev_joystick;
  1002.     joyevent.data1 = joyevent.data2 = joyevent.data3 = 0;
  1003.  
  1004.     if (joypos & JPF_BUTTON_RED)
  1005.       joyevent.data1 |= 1;
  1006.     else
  1007.       joyevent.data1 &= ~1;
  1008.  
  1009.     if (joypos & JP_DIRECTION_MASK) {
  1010.       if (joypos & JPF_JOY_LEFT) {
  1011.         joyevent.data2 = -1;
  1012.       } else if (joypos & JPF_JOY_RIGHT) {
  1013.         joyevent.data2 = 1;
  1014.       }
  1015.       if (joypos & JPF_JOY_UP) {
  1016.         joyevent.data3 = -1;
  1017.       } else if (joypos & JPF_JOY_DOWN) {
  1018.         joyevent.data3 = 1;
  1019.       }
  1020.     }
  1021.  
  1022.     if (joypos & JP_TYPE_GAMECTLR) {
  1023.       event_t event;
  1024.  
  1025.       // Play/Pause = ESC (Menu)
  1026.       if (joypos & JPF_BUTTON_PLAY && !(previous & JPF_BUTTON_PLAY)) {
  1027.         event.type = ev_keydown;
  1028.         event.data1 = KEY_ESCAPE;
  1029.         D_PostEvent (&event);
  1030.       } else if (previous & JPF_BUTTON_PLAY) {
  1031.         event.type = ev_keyup;
  1032.         event.data1 = KEY_ESCAPE;
  1033.         D_PostEvent (&event);
  1034.       }
  1035.  
  1036.       // YELLOW = SHIFT (button 2) (Run)
  1037.       if (joypos & JPF_BUTTON_YELLOW)
  1038.         joyevent.data1 |= 4;
  1039.       else
  1040.         joyevent.data1 &= ~4;
  1041.  
  1042.       // BLUE = SPACE (button 3) (Open/Operate)
  1043.  
  1044.       if (joypos & JPF_BUTTON_BLUE)
  1045.         joyevent.data1 |= 8;
  1046.       else
  1047.         joyevent.data1 &= ~8;
  1048.  
  1049.       // GREEN = RETURN (show msg)
  1050.  
  1051.       if (joypos & JPF_BUTTON_GREEN && !(previous&JPF_BUTTON_GREEN)) {
  1052.         event.type = ev_keydown;
  1053.         event.data1 = 13;
  1054.         D_PostEvent (&event);
  1055.       } else if (previous & JPF_BUTTON_GREEN) {
  1056.         event.type = ev_keyup;
  1057.         event.data1 = 13;
  1058.         D_PostEvent (&event);
  1059.       }
  1060.  
  1061.       // FORWARD & REVERSE - ALT (Button1) Strafe left/right
  1062.  
  1063.       if (joypos & JPF_BUTTON_FORWARD) {
  1064.         joyevent.data1 |= 2;
  1065.         joyevent.data2 = 1;
  1066.       } else if (joypos & JPF_BUTTON_REVERSE) {
  1067.         joyevent.data1 |=2;
  1068.         joyevent.data2=-1;
  1069.       } else
  1070.         joyevent.data1 &= ~2;
  1071.     }
  1072.  
  1073.     D_PostEvent (&joyevent);
  1074.  
  1075.     previous = joypos;
  1076.   }
  1077.  
  1078.   /* SEGA joypad handler code by Joe Fenton, loosely based on CD32 handling */
  1079.  
  1080.   if (sega3_selected || sega6_selected) {
  1081.     event_t joyevent, event;
  1082.  
  1083.     if (sega3_selected) {
  1084.       currSega = Sega3 ();
  1085.     } else {
  1086.       currSega = Sega6 ();
  1087.     }
  1088.  
  1089.     if (prevSega == currSega)
  1090.       return;
  1091.  
  1092.     joyevent.type = ev_joystick;
  1093.     joyevent.data1 = joyevent.data2 = joyevent.data3 = 0;
  1094.  
  1095.     // B = fire
  1096.     if (currSega & 0x10)
  1097.       joyevent.data1 |= 1;
  1098.     else
  1099.       joyevent.data1 &= ~1;
  1100.  
  1101.     // directionals
  1102.     if (currSega & 0xF) {
  1103.       if (currSega & 4) {
  1104.         joyevent.data2 = -1;
  1105.       } else if (currSega & 8) {
  1106.         joyevent.data2 = 1;
  1107.       }
  1108.       if (currSega & 1) {
  1109.         joyevent.data3 = -1;
  1110.       } else if (currSega & 2) {
  1111.         joyevent.data3 = 1;
  1112.       }
  1113.     }
  1114.  
  1115.     // Mode = ESC (Menu)
  1116.     if (currSega & 0x80000 && !(prevSega & 0x80000)) {
  1117.       event.type = ev_keydown;
  1118.       event.data1 = KEY_ESCAPE;
  1119.       D_PostEvent (&event);
  1120.     } else if (prevSega & 0x80000) {
  1121.       event.type = ev_keyup;
  1122.       event.data1 = KEY_ESCAPE;
  1123.       D_PostEvent (&event);
  1124.     }
  1125.  
  1126.     // Y = SHIFT (Run)
  1127.     if (currSega & 0x20000)
  1128.       joyevent.data1 |= 4;
  1129.     else
  1130.       joyevent.data1 &= ~4;
  1131.  
  1132.     // Start = SPACE (Open/Operate)
  1133.     if (currSega & 0x2000)
  1134.       joyevent.data1 |= 8;
  1135.     else
  1136.       joyevent.data1 &= ~8;
  1137.  
  1138.     // A & C - ALT (Button1) Strafe left/right
  1139.     if (currSega & 0x20) {
  1140.       joyevent.data1 |= 2;
  1141.       joyevent.data2 = 1;
  1142.     } else if (currSega & 0x1000) {
  1143.       joyevent.data1 |=2;
  1144.       joyevent.data2=-1;
  1145.     } else
  1146.       joyevent.data1 &= ~2;
  1147.  
  1148.     // X = RETURN (show msg)
  1149.     if (currSega & 0x40000 && !(prevSega&0x40000)) {
  1150.       event.type = ev_keydown;
  1151.       event.data1 = 13;
  1152.       D_PostEvent (&event);
  1153.     } else if (prevSega & 0x40000) {
  1154.       event.type = ev_keyup;
  1155.       event.data1 = 13;
  1156.       D_PostEvent (&event);
  1157.     }
  1158.  
  1159.     // Z = TAB (show map)
  1160.     if (currSega & 0x10000 && !(prevSega&0x10000)) {
  1161.       event.type = ev_keydown;
  1162.       event.data1 = 9;
  1163.       D_PostEvent (&event);
  1164.     } else if (prevSega & 0x10000) {
  1165.       event.type = ev_keyup;
  1166.       event.data1 = 9;
  1167.       D_PostEvent (&event);
  1168.     }
  1169.  
  1170.     D_PostEvent (&joyevent);
  1171.  
  1172.     prevSega = currSega;
  1173.   }
  1174.  
  1175. }
  1176.  
  1177. /**********************************************************************/
  1178. static void calc_time (ULONG time, char *msg)
  1179. {
  1180.   printf ("Total %s = %u us  (%u us/frame)\n", msg, time, time / total_frames);
  1181. }
  1182.  
  1183. /**********************************************************************/
  1184. void _STDvideo_cleanup (void)
  1185. {
  1186.   I_ShutdownGraphics ();
  1187.   if (video_smr != NULL) {
  1188.     FreeAslRequest (video_smr);
  1189.     video_smr = NULL;
  1190.   }
  1191.   if (total_frames > 0) {
  1192.     printf ("Total number of frames = %u\n", total_frames);
  1193.     calc_time (wpa8_time, "WritePixelArray8 time ");
  1194.     calc_time (lock_time, "LockBitMap time       ");
  1195. #ifdef PROFILE
  1196.     {
  1197.       int i;
  1198.  
  1199.       for (i=0; i<32; i++)
  1200.         calc_time (profile[n][2], "Profile Time ");
  1201.     }
  1202. #endif
  1203.   }
  1204. }
  1205.  
  1206. /**********************************************************************/
  1207.